/*
*       A simple 2D game map editor
*
*       This library is free software; you can redistribute it and/or
*       modify it under the terms of the GNU Lesser General Public
*       License as published by the Free Software Foundation; either
*       version 2.1 of the License, or (at your option) any later version.
*/
// Name        : tileset
// File        : tileset.h
// Description :
// Author      : hoha
// Date        : 01/07/2009
// Evolutions  : 01/07/2009, Version V0, Creation
//INCLUDES
#include "widget_tileset.h"
#include "gm_tileset.h"

Wt_TileSet::Wt_TileSet(QWidget *parent)
    : QWidget(parent)
{
    //init tileset size
    tileset_width=TILE_WIDTH*GRID_H_NUM;
    tileset_height=TILE_HEIGHT*GRID_V_NUM;
    this->setMinimumSize(tileset_width,tileset_height);
    //init grid
    grid=NULL;
    grid_line_number=0;
    init_grid(GRID_H_NUM, GRID_V_NUM);
    //init default selected tile
    selected_tile_index =0;
    //
    max_value_of_used_index = 0;
    //initialize tileset data memory
    tileset = NULL;
    tileset = (tileset_mem_t*)malloc(sizeof(tileset_mem_t));
    if(NULL!=tileset)
    {
        memset(tileset,0,sizeof(tileset_mem_t));
        init_tileset_mem(tileset);
    }
    //init locking rect
    selected_tile_rect.setRect(0,0,0,0);
}

Wt_TileSet::~Wt_TileSet()
{
    //free grid memory
    if(NULL!=grid)
    {
        delete[] grid;
        grid = NULL;
    }
    //free tileset's raw data and img memory
    for(int index=0; index < TILE_MAX_NUM; index++)
    {
        if(NULL!=tileset->mem_entry[index].img_data_p)
        {
           delete (tileset->mem_entry[index].img_data_p);
           tileset->mem_entry[index].img_data_p = NULL;
        }
        if(NULL!=tileset->mem_entry[index].raw_data_p)
        {
           free(tileset->mem_entry[index].raw_data_p);
           tileset->mem_entry[index].raw_data_p = NULL;
        }
    }
    //free tileset memory
    if(NULL!=tileset)
    {
        free(tileset);
        tileset=NULL;
    }
}

void Wt_TileSet::paintEvent(QPaintEvent *event)
{
  QPainter painter(this);
  //painter.setRenderHint(QPainter::Antialiasing, true);
  painter.setPen(QColor(34, 139, 34, 70));
  painter.drawLines(grid, grid_line_number);
  //------------------------------------------------------------------
  for(int index =0; index <TILE_MAX_NUM ; index++)
  {
      if((true==tileset->mem_entry[index].entry.isValid)&&(NULL!=tileset->mem_entry[index].img_data_p))
      {
          painter.drawPixmap(tileset->mem_entry[index].draw_pos_x, \
                             tileset->mem_entry[index].draw_pos_y, \
                            (tileset->mem_entry[index].img_data_p->scaled(TILE_WIDTH, TILE_HEIGHT, Qt::KeepAspectRatio)),\
                             0, 0, tileset->mem_entry[index].img_data_p->width(),\
                             tileset->mem_entry[index].img_data_p->height());

      }
  }
  //------------------------------------------------------------------
  painter.setPen(QColor(255, 0, 0, 100));
  painter.drawRect(selected_tile_rect);
}

bool Wt_TileSet::loadFile(QString filename)
{
   bool result = true;
   //check file name
   if(filename.isEmpty())
   {
         COM_MSBOX_WARNING("Tileset:loadfile-->cannot load tileset with empty name!");
         return false;
   }
   //open file
   FILE *fp = NULL;
   fp=fopen(filename.toAscii().data(),"rb+");
   if(NULL==fp)
   {
         COM_MSBOX_WARNING("Tileset:loadfile-->open tileset failed!");
     return false;
   }
   //read tileset Entry.
   for(int i =0; i< TILE_MAX_NUM; i++)
   {
      if(1!=fread(&(tileset->mem_entry[i].entry),sizeof(tileset_entry_t),1,fp))
      {
         COM_MSBOX_WARNING("Tileset:loadfile-->read entry failed!");
             result = false;
             break;
      }
   }
   if(false == result)
   {
         fclose(fp);
         return false;
   }
   //read img data
   for(int index =0; index< TILE_MAX_NUM; index++)
   {
      if(true == tileset->mem_entry[index].entry.isValid)
      {
         tileset->mem_entry[index].raw_data_p = (unsigned char*)malloc(tileset->mem_entry[index].entry.tile_size);
         if(1!=fread(tileset->mem_entry[index].raw_data_p,tileset->mem_entry[index].entry.tile_size,1,fp))
         {
           COM_MSBOX_WARNING("Tilset:loadfile-->read img data failed!");
           result = false;
               break;
         }
         tileset->mem_entry[index].img_data_p = new QPixmap();
         tileset->mem_entry[index].img_data_p->loadFromData(tileset->mem_entry[index].raw_data_p,\
                                                            tileset->mem_entry[index].entry.tile_size);
             //caculate tile bliting position, reimplement if needed
         tileset->mem_entry[index].draw_pos_x =((index%GRID_H_NUM)*TILE_WIDTH);
         tileset->mem_entry[index].draw_pos_y =((index/GRID_V_NUM)*TILE_HEIGHT);
         tileset->head.tile_num++;
      }
   }
   //close file
   fclose(fp);
   //update screen
   update();
   return result;
}

bool Wt_TileSet::saveFile(QString filename)
{
   //
   is_modified = false;
   bool result = true;
   FILE *fp = NULL;
   fp=fopen(filename.toAscii().data(),"wb+");
   if(NULL!=fp)
   {
      //write entry into file
      for(int index =0; index < TILE_MAX_NUM; index++)
      {
        if(1!=fwrite(&(tileset->mem_entry[index].entry),sizeof(tileset_entry_t), 1, fp))
        {
           COM_MSBOX_CRITICAL("Tileset:savefile-->write entry to file failed!");
               result= false;
           break;
        }
      }
          if(false==result)
          {
                fclose(fp);
                return false;
          }
      //write image data into file
      for(int index =0; index < TILE_MAX_NUM; index++)
      {
        if(true == tileset->mem_entry[index].entry.isValid)
        {
           if(1!=fwrite((tileset->mem_entry[index].raw_data_p),tileset->mem_entry[index].entry.tile_size, 1, fp))
           {
              COM_MSBOX_CRITICAL("write img data to file failed!");
                  result = false;
                  break;
           }
        }
      }
      fclose(fp);
      return result;
   }
   else
   {
      COM_MSBOX_CRITICAL("Tileset:savefile-->open file failed");
      return false;
   }
}

bool Wt_TileSet::addTile()
{
   //
   is_modified = true;
   QString fn = QFileDialog::getOpenFileName(this, tr("Open Tile..."),QString(),tr("PNG-Files (*.png);;All Files (*)"));
   if(fn.isEmpty())return false;
   char *file_path_name=fn.toAscii().data();
   //check selected tile index validation
   if(selected_tile_index >= TILE_MAX_NUM)
   {
       printf("selected index %d is not valid\n", selected_tile_index);
       return false;
   }
   if(true==tileset->mem_entry[selected_tile_index].entry.isValid)
   {
       COM_MSBOX_WARNING("this cell is filled already !");
       return false;
   }
   if(false==load_img_data_to_fill(file_path_name,tileset,selected_tile_index))
   {
       printf("load_img_data_to_fill:false\n");
       return false;
   }
   //update screen
   update();
   return true;
}
bool Wt_TileSet::delTile()
{
   is_modified = true;
   if(false == tileset->mem_entry[selected_tile_index].entry.isValid)
   {
      COM_MSBOX_WARNING("this cell is empty, cannot delete!");
      return false;
   }
   //free img data
   free(tileset->mem_entry[selected_tile_index].raw_data_p);
   tileset->mem_entry[selected_tile_index].raw_data_p= NULL;
   //free memory data
   delete tileset->mem_entry[selected_tile_index].img_data_p;
    tileset->mem_entry[selected_tile_index].img_data_p =NULL;

   tileset->mem_entry[selected_tile_index].entry.tile_size=COM_U32_NS;
   tileset->mem_entry[selected_tile_index].entry.tile_height =COM_U16_NS;
   tileset->mem_entry[selected_tile_index].entry.tile_width = COM_U16_NS;
   tileset->mem_entry[selected_tile_index].entry.isValid=false;
   tileset->mem_entry[selected_tile_index].draw_pos_x =COM_U32_NS;
   tileset->mem_entry[selected_tile_index].draw_pos_y =COM_U32_NS;
   tileset->head.tile_num--;
   update();
   return true;
}
void Wt_TileSet::mousePressEvent(QMouseEvent *event)
{
   if(event->x()<=(GRID_CELL_WIDTH*GRID_CELL_WIDTH)&&(event->y()<GRID_CELL_HEIGHT*GRID_CELL_HEIGHT))
   {
       selected_tile_index = ((event->y())/GRID_CELL_HEIGHT)*GRID_H_NUM + (event->x())/GRID_CELL_WIDTH;
       locked_tile = selected_tile_index;
       u32 rect_x = ((event->x())/GRID_CELL_WIDTH)*GRID_CELL_WIDTH;
       u32 rect_y = ((event->y())/GRID_CELL_HEIGHT)*GRID_CELL_HEIGHT;
       selected_tile_rect.setRect(rect_x, rect_y, GRID_CELL_WIDTH, GRID_CELL_HEIGHT);
   }
   //update(selected_tile_rect);
   update();
}

void Wt_TileSet::init_grid(u16 h_cell_num, u16 v_cell_num)
{
    grid_line_number = (h_cell_num+1)+(v_cell_num+1);
    grid = new QLine[grid_line_number];
    for(u16 i=0; i< grid_line_number; i++)
    {
        if(i < (v_cell_num+1))
        {
           // Harizon lines
           grid[i].setLine(0,i*GRID_CELL_HEIGHT, h_cell_num*GRID_CELL_WIDTH, i*GRID_CELL_HEIGHT);
        }
        else
        {
           //vertical lines
           grid[i].setLine((i-(v_cell_num+1))*GRID_CELL_WIDTH, 0,\
                            (i-(v_cell_num+1))*GRID_CELL_WIDTH, v_cell_num*GRID_CELL_HEIGHT);
        }
    }
}

bool Wt_TileSet::load_img_data_to_fill(const char* file_path, tileset_mem_t* ts, u16 index)
{
   FILE *fp;
   //open file
   fp=fopen(file_path,"rb");
   if(NULL == fp)
   {
           COM_MSBOX_CRITICAL("Tileset::load_img_data_to_fill-->failed to open file!");
           return false;
   }
   u32 len = com_get_file_size(fp);
   ts->mem_entry[index].raw_data_p = (unsigned char*)malloc(len);
   //read file
   if(1!=fread(ts->mem_entry[index].raw_data_p, len, 1, fp))
   {
           COM_MSBOX_CRITICAL("Tileset::load_img_data_to_fill-->failed to read file!");
           fclose(fp);
           return false;
   }
   //close file
   fclose(fp);
   //fill data
   ts->mem_entry[index].entry.tile_size=len;
   ts->mem_entry[index].img_data_p = new QPixmap();
   ts->mem_entry[index].img_data_p->loadFromData(ts->mem_entry[index].raw_data_p,\
                                                 ts->mem_entry[index].entry.tile_size);
   ts->mem_entry[index].entry.tile_height = ts->mem_entry[index].img_data_p->height();
   ts->mem_entry[index].entry.tile_width =  ts->mem_entry[index].img_data_p->width();
   ts->mem_entry[index].entry.isValid=true;
   //caculate bliting position, reimplement if needed
   ts->mem_entry[index].draw_pos_x =((index%GRID_H_NUM)*TILE_WIDTH);
   ts->mem_entry[index].draw_pos_y =((index/GRID_V_NUM)*TILE_HEIGHT);
   ts->head.tile_num++;
   return true;
}
bool Wt_TileSet::init_tileset_mem(tileset_mem_t* ts)
{
   ts->head.tile_num = 0;
   for(u16 i =0; i<TILE_MAX_NUM; i++)
   {
      ts->mem_entry[i].raw_data_p=NULL;
      ts->mem_entry[i].img_data_p=NULL;
      ts->mem_entry[i].entry.data_offset = COM_U32_NS;
      ts->mem_entry[i].entry.tile_height = COM_U16_NS;
      ts->mem_entry[i].entry.tile_width = COM_U16_NS;
      ts->mem_entry[i].entry.tile_size = COM_U32_NS;
      ts->mem_entry[i].entry.isValid = false;
      ts->mem_entry[i].draw_pos_x = COM_U32_NS;
      ts->mem_entry[i].draw_pos_y = COM_U32_NS;
   }
   return true;
}
